package com.genexususa.eo.google.connection;

import com.genexususa.eo.google.data.*;
import com.genexususa.eo.google.exceptions.ConnectionException;
import com.google.api.ads.adwords.axis.v201409.cm.*;
import com.google.api.ads.adwords.axis.v201409.mcm.*;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.rmi.RemoteException;
import java.util.ArrayList;


public class AccountManager {

    private String _clientId;

    public void SetClientId(String clientId) {
        this._clientId = clientId;
    }

    public String GetClientId() {
        return _clientId;
    }

    public void Finalize() {

        SessionController sc = SessionController.getInstance();
        sc.RemoveSession(_clientId);
    }

    private static final int PAGE_SIZE = 2000;


    public String CreateAccountParameters(String name, String currencyCode, String dateTimeZone){

        String file = "<GA_AccountCollection xmlns=\"L2TMediaTrunk\">\n" +
                "       <GA_Account xmlns=\"L2TMediaTrunk\">\n" +
                "              <Id>0</Id>\n" +
                "              <AccountGxId>37</AccountGxId>\n" +
                "              <Name>" + name + "</Name>\n" +
                "              <CurrencyCode>"+currencyCode+"</CurrencyCode>\n" +
                "              <DateTimeZone>"+dateTimeZone+"</DateTimeZone>\n" +
                "       </GA_Account>\n" +
                "</GA_AccountCollection>\n";

        return CreateAccount(file);

    }


    public String CreateAccount(String xml) {
        try {

            String result = "";

            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();

            // Get Managed Customer Service
            ManagedCustomerServiceInterface managedCustomerService = sf.GetManagedCustomerService(this.GetClientId());


            // GA_ResultCreateAccounts res = new GA_ResultCreateAccounts();

            GA_Result res = new GA_Result();

            try {

                Util util = new Util();

                Document doc = util.loadXMLFromString(xml);

                XPathFactory factory = XPathFactory.newInstance();
                XPath xpath = factory.newXPath();

                XPathExpression expr
                        = xpath.compile("//GA_Account");

                Object accountsNodes = expr.evaluate(doc, XPathConstants.NODESET);

                NodeList accounts = (NodeList) accountsNodes;

                ArrayList<GA_ResultItem> createdAccounts = new ArrayList<GA_ResultItem>();

                if (accounts.getLength() > 0) {

                    for (int i = 0; i < accounts.getLength(); i++) { // For all GA_Account Nodes

                        Node n = accounts.item(i);

                        NodeList children = n.getChildNodes();

                        //GA_Account account = new GA_Account();
                        GA_ResultItem account = new GA_ResultItem();

                        ManagedCustomer customer = new ManagedCustomer();

                        if (children.getLength() > 0) {


                            for (int j = 0; j < children.getLength(); j++) {

                                if (children.item(j).getNodeName().equalsIgnoreCase("AccountGxId")) {
                                    account.AccountGxId = Long.parseLong(children.item(j).getTextContent());
                                }

                                if (children.item(j).getNodeName().equalsIgnoreCase("Name")) {
                                    customer.setName(children.item(j).getTextContent());
                                }

                                if (children.item(j).getNodeName().equalsIgnoreCase("CurrencyCode")) {
                                    customer.setCurrencyCode(children.item(j).getTextContent());
                                }

                                if (children.item(j).getNodeName().equalsIgnoreCase("DateTimeZone")) {
                                    customer.setDateTimeZone(children.item(j).getTextContent());
                                }

                            }

                            account.Customer = customer;

                            createdAccounts.add(account);


                        }

                    }

                    ArrayList<GA_ResultItem> created = new ArrayList<GA_ResultItem>();

                    for (GA_ResultItem account : createdAccounts) {

                        GA_ResultItem createAccount = new GA_ResultItem();

                        createAccount.AccountGxId = account.AccountGxId;

                        /*ManagedCustomer customer = new ManagedCustomer();

                        customer.setCurrencyCode(account.CurrencyCode);
                        customer.setDateTimeZone(account.DateTimeZone);
                        customer.setName(account.Name);*/

                        ManagedCustomerOperation operation = new ManagedCustomerOperation();
                        operation.setOperand(account.Customer);
                        operation.setOperator(Operator.ADD);

                        ManagedCustomerOperation[] operations = new ManagedCustomerOperation[]{operation};

                        try {

                            ManagedCustomerReturnValue resultValue = managedCustomerService.mutate(operations);
                            Thread.sleep(1000);
                            createAccount.AccountId = resultValue.getValue(0).getCustomerId();
                            created.add(createAccount);

                        } catch (ApiException apiException) {

                            ApiError[] apiErrors = apiException.getErrors();

                            createAccount.AccountId = 0L;
                            createAccount.HasError = true;
                            createAccount.setRegularErrorType();

                            for (ApiError apiError : apiErrors) {

                                ErrorsStruct errors = new ErrorsStruct();
                                errors.Message = apiError.getErrorString();
                                errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();
                                com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();
                                err.ErrorString = apiError.getErrorString();
                                err.fieldPath = apiError.getFieldPath();
                                err.Reason = apiException.getFaultReason();
                                err.Trigger = apiError.getTrigger();
                                err.Type = apiError.getApiErrorType();
                                errors.Errors.add(err);
                                createAccount.Errors = errors;
                                created.add(createAccount);
                            }


                        }

                    }

                    try {

                        JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                        Marshaller marshallerObj = contextObj.createMarshaller();
                        marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                        StringWriter sw = new StringWriter();

                        res.Items = created;

                        marshallerObj.marshal(res, sw);
                        result = sw.getBuffer().toString();
                        System.out.println(result);
                        String s = "";

                    } catch (Exception exc) {
                        exc.printStackTrace();
                        result = exc.getMessage();
                    }

                }


            } catch (Exception exc) {

                exc.printStackTrace();
                result = exc.getMessage();

            }

            return result;
        } catch (Exception exc) {
            GA_Result res = new GA_Result();
            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();
            GA_ResultItem error = new GA_ResultItem();
            ErrorsStruct errors = new ErrorsStruct();
            errors.Message = exc.getMessage();
            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();
            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();
            errors.Errors.add(err);
            error.Errors = errors;
            error.HasError = true;
            if (exc instanceof ConnectionException) {
                error.setNoResponseErrorType();
                err.UnknownError = "Connection error";
            } else {
                error.setRegularErrorType();
                StringWriter st = new StringWriter();
                exc.printStackTrace(new PrintWriter(st));
                err.UnknownError = st.toString();
            }
            items.add(error);

            String result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }
    }


    public ArrayList<GA_Account> GetAllAccounts() {

        ArrayList<GA_Account> result = new ArrayList<GA_Account>();

        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get campaign service
            ManagedCustomerServiceInterface managedCustomerService = sf.GetManagedCustomerService(this.GetClientId());

            int offset = 0;
            Selector selector = new Selector();

            selector.setPaging(new Paging(offset, PAGE_SIZE));
            selector.setFields(new String[]{"CustomerId", "Name", "CurrencyCode", "DateTimeZone"});

            ManagedCustomerPage page = null;


            try {

                do {

                    page = managedCustomerService.get(selector);


                    if (page.getEntries() != null) {

                        for (ManagedCustomer customer : page.getEntries()) {
                            GA_Account account = new GA_Account();
                            account.AccountGxId = customer.getCustomerId();
                            account.CurrencyCode = customer.getCurrencyCode();
                            account.DateTimeZone  = customer.getDateTimeZone();
                            account.Name = customer.getName();
                            result.add(account);
                            System.out.println("Id: " + customer.getCustomerId() + ", Name: " + customer.getName());

                        }

                    }

                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);

                } while (offset < page.getTotalNumEntries());


            } catch (RemoteException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }

        return result;

    }

    public AccountReport GetAccountReport(String clientId) {

        AccountReport result = new AccountReport();

        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get Managed Customer Service
            ManagedCustomerServiceInterface managedCustomerService = sf.GetManagedCustomerService(clientId);

            int offset = 0;
            Selector selector = new Selector();

            selector.setPaging(new Paging(offset, PAGE_SIZE));
            //selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)});

            selector.setFields(new String[]{
                    "CurrencyCode",
                    "CustomerId",
                    "DateTimeZone",
                    "Name"
            });


            // Create predicates.
            Predicate accountIdPredicate =
                    new Predicate("CustomerId", PredicateOperator.IN, new String[]{clientId});
            selector.setPredicates(new Predicate[]{accountIdPredicate});

            ManagedCustomerPage page = null;


            try {

                do {

                    page = managedCustomerService.get(selector);

                    if (page.getEntries() != null) {

                        for (ManagedCustomer managedCustomer : page.getEntries()) {
                            result.CurrencyCode = managedCustomer.getCurrencyCode();
                            result.CustomerId = managedCustomer.getCustomerId();
                            result.DateTimeZone = managedCustomer.getDateTimeZone();
                            result.Name = managedCustomer.getName();
                        }


                    }


                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);

                } while (offset < page.getTotalNumEntries());


            } catch (Exception exc) {
                exc.printStackTrace(System.out);
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }

        return result;
    }
}
